/**
 * 转换时间格式插件
 * @param {*} schema 数据库schema
 * @param {Object}  {
 * @param create: 自生成创建时间字段名
 * @param update: 自生成修改时间字段名
 * @param paths {Array}: 需要转换时间格式的字段。
 * 支持：
 * 字段：paths:['start_time'] => 数据{start_time: 日期}
 * 对象：paths: ['dates.start_time'] => 数据{dates: {start_time: 日期}}
 * 对象数组：paths: ['dates.*.start_time'] => 数据{dates:[{start_time: 日期},{start_time: 日期}]}
 * 对象中嵌套数组： paths: ['dates.range.*.start_time'] => 数据{dates:{range:[{start_time: 日期}]}}
 * }
 */
const dayjs = require("dayjs");

function transDatePlugin(schema, { created = 'create_time', updated = 'update_time', paths = [] }) {
    function transDate(type = 'save') {
        let timestamps = []
        if (created) timestamps.push(created)
        if (updated) timestamps.push(updated)
        paths = paths.filter(i => i !== created && i !== updated)
        return function (next, docs) {
            if (this.isNew && !this.constructor.$isArraySubdocument) { // 新增单条数据
                timestamps.forEach(field => { // 新增/修改时间
                    this[field] = formatDate()
                })
                formatFn(this, paths)
                return next()
            }
            if (type === 'insertMany') { // 新增多条数据
                docs.forEach(item => {
                    timestamps.forEach(field => { // 新增/修改时间
                        item[field] = formatDate()
                    })
                    formatFn(item, paths)
                })
                return next()
            }
            // 修改数据时
            if (type === 'update') {
                if (updated && this._update.$set[updated]) this._update.$set[updated] = formatDate()
                formatFn(this._update, paths)

                formatFn(this._update.$set, paths)
            } else {
                if (updated && this[updated]) this[updated] = formatDate()
                formatFn(this, paths)
            }
            next()
        }
    }

    schema.pre('save', transDate()) // 新建/保存数据
    schema.pre('insertMany', transDate('insertMany')) // 批量插入数据
    schema.pre('updateMany', transDate('update')) // 批量修改数据
    schema.pre('updateOne', transDate('update')) // 修改单条数据
    schema.pre('findOneAndUpdate', transDate('update')) // 找到一条数据并修改
}
function formatDate(baseDate, fmt = "YYYY-MM-DD HH:mm:ss") {
    let date;
    if (baseDate || baseDate !== undefined) {
        if (isNaN(baseDate)) {
            date = new Date()
        } else date = new Date(baseDate)
    }
    return dayjs(date).format(fmt)
}
function formatFn(obj, paths = [], retDataKey = false) {
    let objBak = obj
    paths.forEach(item => {
        obj = objBak
        if (item.indexOf('.*.') >= 0) {
            let pArr = item.split('.*.')
            pArr.forEach((ai, aidx) => {
                if (aidx === pArr.length - 1) {
                    if (!obj) return
                    obj.forEach(aci => {
                        formatFn(aci, [ai])
                    })
                } else {
                    obj = formatFn(obj, [ai], true)
                }
            })
        } else if (item.indexOf('.*') >= 0) {
            let pArr = item.split('.*')
            pArr.some((ai, aidx) => {
                if (!ai) return false
                obj = formatFn(obj, [ai], true)
                obj.some((aci, acidx) => {
                    if (toString.call(aci) === '[object Object]') return false
                    if (obj[acidx]) obj[acidx] = formatDate(aci)
                })
            })
        } else {
            let pobj = item.split('.')
            pobj.forEach((pi, pidx) => {
                if (pidx === pobj.length - 1 && !retDataKey) {
                    if (obj[pi]) obj[pi] = formatDate(obj[pi])
                } else obj = obj[pi]
            })
        }
    })
    if (retDataKey) return obj
}

module.exports = transDatePlugin